//
//  pantomime_controller.m
//  sbrush
//
//  Created by Phillip Popp on 4/25/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "pantomime_controller.h"
#import "sbrush_instrument_view_updater.h"
#import "file_dialogue.h"
#import "sbrush_spectral_model.h"
#import "sms_item.h"
#import "pantomime_item.h"

#include <memory>

using namespace std;
using namespace sbrush;

namespace {
	unsigned n_countdown_val = 0;
	unsigned n_countdown_init_val = 3;
	
	void on_sms_player_finished(const Player* player, void* userData) {
		if (userData != NULL) {
			PantomimeController* controller = (PantomimeController*)userData;
			[controller finishPlaySms];
		}
	}
	
	void on_pantomime_player_finished(const Player* player, void* userData) {
		if (userData != NULL) {
			PantomimeController* controller = (PantomimeController*)userData;
			[controller finishPantomimePlayback];
		}
	}
	
	void pantomime_record_cb(PantomimeRecorder* archiver, 
							 PantomimeAction action,
							 void* userData) {
		PantomimeController* controller = (PantomimeController*)userData;
		if (controller != NULL) {
			if (action == Pantomime_Prepare) {
				n_countdown_val = n_countdown_init_val;
				[controller startCountdown];
			}
			else if (action == Pantomime_Countdown) {
				[controller countdown:n_countdown_val];
				if (n_countdown_val == 0) {
					[controller finishCountdown];
				}
				else {
					n_countdown_val--;
				}
			}
			else if (action == Pantomime_Finish) {
				[controller finishPantomimeRecording];
			}
		}
	}
	
	void pantomime_practice_cb(PantomimeRecorder* archiver, 
							   PantomimeAction action,
							   void* userData) {
		if (action == Pantomime_Finish) {
			PantomimeController* controller = (PantomimeController*)userData;
			[controller finishPractice];
		}
	}
}


@implementation PantomimeController

@synthesize smsItems;
@synthesize pantomimeItems;

- (id)init {
	[NSException raise:@"unsupported init" format:@"must init using initWithSmsArray"];
	return self;
}

- (id)initWithSmsArray:(NSMutableArray*)sms 
		pantomimeArray:(NSMutableArray*)pantomimes
		 pantomimeView:(NSView*)view
		instrumentView:(InstrumentView*)instView
			instrument:(sbrush::Instrument*)instrument;
{
    self = [super initWithWindowNibName:@"Pantomime"];
    if (self != nil) {
		smsItems = sms;
		pantomimeItems = pantomimes;
		pantomimeSubView = view;
		_instrumentView = instView;
		_viewUpdater = new InstrumentViewUpdater();
		instrument->addListener(_viewUpdater);
		[pantomimeSubView setFrame:NSMakeRect(0, 0, 200, 200)];
		_viewUpdater->setInstrumentView(_instrumentView);
		_spectralModelPlayer = new SpectralModelPlayer();
		_spectralModelPlayer->setFinishedCallback(on_sms_player_finished,
												  self);
		_pantomimeRecorder = new PantomimeRecorder();
		instrument->addListener(_pantomimeRecorder);
		_pantomimePlayer = new PantomimePlayer();
		_pantomimePlayer->addListener(_viewUpdater);
		_pantomimePlayer->setFinishedCallback(on_pantomime_player_finished,
											  self);
    }    
    return self;
}

- (void)windowDidLoad {
	[pantomimeView addSubview:pantomimeSubView];
}

- (void) dealloc {
	_instrument->removeListener(_viewUpdater);
	_instrument->removeListener(_pantomimeRecorder);
	_pantomimePlayer->removeListener(_viewUpdater);
	delete _viewUpdater;
	delete _spectralModelPlayer;
	delete _pantomimeRecorder;
	delete _pantomimePlayer;
	[[pantomimeSubView retain] removeFromSuperview];
	[super dealloc];
}

- (IBAction) loadSms:(id)sender {
	NSArray* fileItems = [FileDialogue openModalWithTitle:@"Open Spectral Model"
												extension:@"sms"];

	for (unsigned i = 0; i < [fileItems count]; i++) {
		NSError* anError = nil;
		SmsItem* smsItem = [[SmsItem alloc] initFromExisting:[fileItems objectAtIndex:i]];
		if ([smsItem readFromFile:&anError]) {
			[[self mutableArrayValueForKey:@"smsItems"] addObject:smsItem];
		}
		else {
			NSAlert* alert = nil;
			if (anError != nil) {
				alert = [NSAlert alertWithError:anError];
			}
			else {
				alert = [NSAlert alertWithMessageText:@"Failed to load Spectral Model"
												 defaultButton:nil
											   alternateButton:nil 
												   otherButton:nil
									 informativeTextWithFormat:@""];
			}
			[alert setAlertStyle:NSWarningAlertStyle];
			[alert runModal];
		}
	}
}

- (void)setSmsItems:(NSMutableArray *)array {
	/* we only copy the values here because other objects have references to
	 * smsItems */
	[smsItems setArray:array];
}

- (void)setPantomimeItems:(NSMutableArray *)array {
	/* we only copy the values here because other objects have references to
	 * smsItems */
	[pantomimeItems setArray:array];
}

- (IBAction) startPractice:(id)sender {
	[self stopAll];
	SpectralModel* model = [self getCurrentSpectralModel];
	if (model != NULL) {
		//[self startInstrumentDraw];
		_pantomimeRecorder->setCallback(pantomime_practice_cb, self);
		_pantomimeRecorder->start(*model, n_countdown_init_val, 1.0);
	}
}

- (void) finishPractice {
	[self stopAll];
	_pantomimeRecorder->clear();
}

- (IBAction) startPantomimeRecording:(id)sender {
	[self stopAll];
	_pantomimeRecorder->clear();
	SpectralModel* model = [self getCurrentSpectralModel];
	if (model != NULL) {
		//[self startInstrumentDraw];
		_pantomimeRecorder->setCallback(pantomime_record_cb, self);
		_pantomimeRecorder->start(*model, n_countdown_init_val, 1.0);
	}
}

- (void) finishPantomimeRecording {
	[self stopAll];
	auto_ptr<Pantomime> newPantomime = _pantomimeRecorder->getPantomime();
	if (newPantomime.get() != NULL) {
		PantomimeItem* newPantomimeItem = [[PantomimeItem alloc] init];
		[newPantomimeItem setPath:@""];
		[newPantomimeItem setDisplay:[NSString stringWithFormat:@"*pantomime_%d", 
								  [pantomimeItems count]]];
		[newPantomimeItem setSaved:NO];
		[newPantomimeItem setPantomime:newPantomime.release()];
		[[self mutableArrayValueForKey:@"pantomimeItems"] addObject:newPantomimeItem];
	}
}

- (void) startCountdown {
	[_instrumentView startCountdown];
}

- (void) countdown:(unsigned)tminus {
	[_instrumentView displayCountdown:tminus];
}

- (void) finishCountdown {
	[_instrumentView finishCountdown];
}

- (IBAction) playSms:(NSButton*)sender {
	if ([sender state] == NSOnState) {
		[self stopPlaySms:sender];
	} else {
		[self startPlaySms:sender];
	}
}

- (IBAction) startPlaySms:(id)sender {
	[self stopAll];
	NSArray* selectedObjs = [smsItemsController selectedObjects];
	if ([selectedObjs count] > 0) {
		SmsItem* smsItem = [selectedObjs objectAtIndex:0];
		/* attempt to open from file */
		_spectralModelPlayer->stop();
		if ([smsItem spectralModel] != NULL) {
			_spectralModelPlayer->setModel(*[smsItem spectralModel]);
			_spectralModelPlayer->start();
		}
	}
	else {
		[self finishPlaySms];
	}
}

- (IBAction) stopPlaySms:(id)sender {
	_spectralModelPlayer->stop();
}

- (void) finishPlaySms {
	[playSmsButton setState:NSOnState];
}

- (IBAction) loadPantomime:(id)sender {
	NSArray* fileItems = [FileDialogue openModalWithTitle:@"Open Pantomime"
												extension:@"ptm"];
	
	for (unsigned i = 0; i < [fileItems count]; i++) {
		NSError* anError = nil;
		PantomimeItem* pantomimeItem = [[PantomimeItem alloc] 
										initFromExisting:[fileItems objectAtIndex:i]];
		if ([pantomimeItem readFromFile:&anError]) {
			[[self mutableArrayValueForKey:@"pantomimeItems"] addObject:pantomimeItem];
		}
		else {
			NSAlert* alert = nil;
			if (anError != nil) {
				alert = [NSAlert alertWithError:anError];
			}
			else {
				alert = [NSAlert alertWithMessageText:@"Failed to load Pantomime"
												 defaultButton:nil
											   alternateButton:nil 
												   otherButton:nil
									 informativeTextWithFormat:@""];
			}
			[alert setAlertStyle:NSWarningAlertStyle];
			[alert runModal];
		}
	}
}

- (IBAction) pantomimePlayback:(NSButton*)sender {
	if ([sender state] == NSOffState) {
		[self startPantomimePlayback:sender];
	} else {
		[self stopPantomimePlayback:sender];
	}
}

- (IBAction) startPantomimePlayback:(id)sender {
	[self stopAll];
	Pantomime* pantomime = [self getCurrentPantomime];
	if (pantomime != NULL) {
		_pantomimePlayer->setPantomime(*pantomime);
		_pantomimePlayer->start();
	}
	else {
		[self finishPantomimePlayback];
	}
}

- (IBAction) stopPantomimePlayback:(id)sender {
	_pantomimePlayer->stop();
}

- (void) finishPantomimePlayback {
	[playPantomimeButton setState:NSOnState];
}

- (void) startInstrumentDraw {
	_viewUpdater->setInstrumentView(_instrumentView);
	//[pantomimeSubView enterFullScreenMode:[[NSScreen screens] objectAtIndex:0]
	//						  withOptions:nil];
}

- (void) stopInstrumentDraw {
	_viewUpdater->setInstrumentView(NULL);
	if ([pantomimeSubView isInFullScreenMode]) {
		[pantomimeSubView exitFullScreenModeWithOptions:nil];
	}
} 

- (void)keyDown:(NSEvent *)theEvent {
	/* save pantomime if someone hits cmd-s */
	if ([theEvent modifierFlags] & NSCommandKeyMask) {
		if ([[theEvent charactersIgnoringModifiers]compare:@"s"] == NSOrderedSame) {
			PantomimeItem* pantomime = [self getCurrentPantomimeItem];
			if (pantomime != nil) {
				[FileDialogue saveModal:pantomime
								  title:@"Save Pantomime"
							  extension:@"ptm"];
			}
		}
	}
	/* kill everything if someone hits esc */
	else if ([theEvent keyCode] == 53){
		[self stopAll];
	}
}

- (SpectralModel*) getCurrentSpectralModel {
	SpectralModel* model = NULL;
	NSArray* selectedObjs = [smsItemsController selectedObjects];
	if ([selectedObjs count] > 0) {
		model = [[selectedObjs objectAtIndex:0] spectralModel];
	}
	return model;
}

- (PantomimeItem*) getCurrentPantomimeItem {
	NSArray* selectedObjs = [pantomimeItemsController selectedObjects];
	if ([selectedObjs count] > 0) {
		return [selectedObjs objectAtIndex:0];
	}
	return nil;
}

- (Pantomime*) getCurrentPantomime {
	PantomimeItem* pItem = [self getCurrentPantomimeItem];
	if (pItem == nil) {
		return NULL;
	}
	return [pItem pantomime];
}

- (void) stopAll {
	_spectralModelPlayer->stop();
	_pantomimePlayer->stop();
	_pantomimeRecorder->cancel();
	if ([pantomimeSubView isInFullScreenMode]) {
		[pantomimeSubView exitFullScreenModeWithOptions:nil];
	}
}

@end
